#include "http_connection.h"

#include "./../socket_module/tcp_socket_connection.h"
#include "./../socket_module/tls_socket_connection.h"

#include <cstdint>
#include <cstdio>
#include <memory>
#include <vector>

HttpConnection::HttpConnection(Loop * loop)
{
    m_loop = loop;
}

void HttpConnection::InitCallbackFn(OnConnectFn && connect, OnMessageFn && message_fn, OnDisConnectFn && dis_connect_fn)
{
    m_on_connect_fn = connect;
    m_on_msg_fn     = message_fn;
    m_on_disconn_fn = dis_connect_fn;
}

int HttpConnection::SendRequest(HttpRequest & request) const
{
    int result = -1;
    if (m_connection)
    {
        result = 0;
        std::string content;
        request.String(content);
        m_connection->AsyncWrite((const uint8_t *)content.data(), content.size());
    }
    return result;
}

void HttpConnection::OnConnection(std::shared_ptr<SocketConnection> conn, int result)
{
    if (result < 0)
    {
        printf("connect to server failed and will close connection data.\n");
        m_connection->Close();
    }
    else
    {
        printf("connect to server success and will read or write message to server.\n");
        m_connection->AsyncRead();
    }
    if (m_on_connect_fn)
    {
        m_on_connect_fn(this, result < 0 ? -1 : 1);
    }
}

void HttpConnection::OnMessage(std::shared_ptr<SocketConnection> conn, int result, SocketConnection::Message & message)
{
    if (result < 0)
    {
        m_connection->Close();
        if (m_on_disconn_fn)
        {
            m_on_disconn_fn(this);
        }
    }
    else
    {
        int       use_length = 0;
        const int ret        = m_parser.ParseHttpResponseProtocol(message.m_data, message.m_data_length, use_length);
        // printf("result %d length : %d and use length : %d.\n", ret, message.m_data_length, use_length);
        if (ret == HttpResponseProtocolParser::FINISH)
        {
            const auto response = m_parser.Response();
            if (m_on_msg_fn)
            {
                m_on_msg_fn(this, response);
            }
            message.m_use_length = use_length;
            m_parser.Clear();
        }
        else if (ret == HttpResponseProtocolParser::NEED_DATA)
        {
            message.m_use_length = use_length;
        }
        else
        {
            message.m_use_length = message.m_data_length;
            m_parser.Clear();
        }
    }
}

void HttpConnection::OnError(std::shared_ptr<SocketConnection> conn, int result)
{
    printf("error result : %d.\n", result);
    m_connection->Close();
    if (m_on_disconn_fn)
    {
        m_on_disconn_fn(this);
    }
}

int HttpConnection::InitHttpConnect(const std::string & host, uint16_t port, int enable_tls)
{
    std::vector<SocketAddress> addr_vec;
    SocketAddress::Address(host, port, addr_vec);
    if (addr_vec.empty())
    {
        return -1;
    }
    if (host[0] >= '9')
    {
        addr_vec.data()->HostName(host);
    }
    SocketAddress addr = *addr_vec.data();
    if (enable_tls)
    {
        m_connection = std::make_shared<TlsSocketConnection>(m_loop);
    }
    else
    {
        m_connection = std::make_shared<TcpSocketConnection>(m_loop);
    }
    m_connection->OpenSocket({}, {});
    m_connection->AsyncConnect(addr, {.m_enable_nonblock = 1});
    return 0;
}

void HttpConnection::Close()
{
    if (m_connection)
    {
        m_connection->Close();
        m_connection = nullptr;
    }
    m_parser.Clear();
}
